/*
 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "sle_ssap_server_server.h"
#include "sle_ssap_server_service.h"
#include "sle_adapter_manager.h"
#include "sle_utils_remote_observer_list.h"
#include "sle_hilog.h"
#include "sle_server_event_handler.h"
#include "sle_advanced_setting_manager.h"

namespace OHOS {
namespace NearLink {
namespace SleStandard {
namespace {
constexpr const char *SLE_SERVER_RUNNER_WORK_THREAD = "SLE_SERVER_RUNNER_WORK_THREAD";
}

class SleSsapServerServer::SleSsapServerServerImpl {
public:
    SleSsapServerServerImpl();
    ~SleSsapServerServerImpl();

    SleErrorCode CheckOperation();
    SleErrorCode RegisterSsapServer(const Uuid &uuid, uint8_t &serverId, const sptr<ISleSsapServerCallback> &callback);
    SleErrorCode UnregisterSsapServerInner(const sptr<ISleSsapServerCallback> &callback, uint8_t serverId);
    SleErrorCode UnregisterSsapServer(uint8_t serverId, const sptr<ISleSsapServerCallback> &callback);
    SleErrorCode AddService(uint8_t serverId, const Uuid &uuid, bool isPrimary, uint16_t &handle);
    SleErrorCode AddProperty(
        uint8_t serverId, uint16_t serviceHandle, const SsapServerPropertyParam &param, uint16_t &handle);
    SleErrorCode AddDescriptor(
        uint8_t serverId, uint16_t serviceHandle, uint16_t propHandle, const SsapServerDescriptorParam &param);
    SleErrorCode RemoveAllServices(uint8_t serverId);
    SleErrorCode StartService(uint8_t serverId, uint16_t serviceHandle);
    SleErrorCode SendResponse(uint8_t serverId, uint16_t connectId, const SsapServerSendRspParam &param);
    SleErrorCode NotifyIndicate(uint8_t serverId, uint16_t connectId, const SsapServerNotifyParam &param);
    SleErrorCode NotifyIndicateByUuid(uint8_t serverId, uint16_t connectId, const SsapServerNotyfyByUuidParam &param);
    SleErrorCode SetServerMtuInfo(uint8_t serverId, uint32_t mtu, uint16_t version);

    class SleSsapServerCallbackImpl;
    std::unique_ptr<SleSsapServerCallbackImpl> callbackImpl_ = nullptr;

    SleSsapServerService *serverService_ = nullptr;
    SleAdapterManager *adapterManager_ = nullptr;
    SleRemoteObserverList<ISleSsapServerCallback, uint8_t> callbacks_;
    std::shared_ptr<AppExecFwk::EventRunner> serverEventRunner_ = nullptr;
    std::shared_ptr<SleServerEventHandler> serverEventHandler_  = nullptr;
};

class SleSsapServerServer::SleSsapServerServerImpl::SleSsapServerCallbackImpl : public ISsapServerCallback {
public:
    SleSsapServerCallbackImpl(SleSsapServerServer::SleSsapServerServerImpl &impl) : impl_(impl) {};
    ~SleSsapServerCallbackImpl() = default;

    void OnStartService(uint8_t serverId, uint16_t handle, SleErrorCode errCode) override
    {
        SLE_LOGD("OnStartService In");
        impl_.callbacks_.ForEach([serverId, handle, errCode](sptr<ISleSsapServerCallback> callback) {
            callback->OnStartService(serverId, handle, errCode);
        });
    }

    void OnAllServiceDelete(uint8_t serverId, SleErrorCode errCode) override
    {
        SLE_LOGD("OnAllServiceDelete In");
        impl_.callbacks_.ForEach([serverId, errCode](sptr<ISleSsapServerCallback> callback) {
            callback->OnAllServiceDelete(serverId, errCode);
        });
    }

    void OnReadRequest(
        uint8_t serverId, uint16_t connectId, const SsapsReqReadCbParam &param, SleErrorCode errCode) override
    {
        SLE_LOGD("OnReadRequest In");
        SsapServerReqReadCbParam params(param);
        impl_.callbacks_.ForEach([serverId, connectId, &params, errCode](sptr<ISleSsapServerCallback> callback) {
            callback->OnReadRequest(serverId, connectId, params, errCode);
        });
    }

    void OnWriteRequest(
        uint8_t serverId, uint16_t connectId, const SsapsReqWriteCbPara &param, SleErrorCode errCode) override
    {
#if 0
        SLE_LOGD("OnWriteRequest In");
#endif
        SsapServerReqWriteCbParam params(param);
        impl_.callbacks_.ForEach([serverId, connectId, &params, errCode](sptr<ISleSsapServerCallback> callback) {
            callback->OnWriteRequest(serverId, connectId, params, errCode);
        });
    }

    void OnMtuInfoChanged(uint8_t serverId, uint16_t connectId, const SsapMtuInfo &info, SleErrorCode errCode) override
    {
        SLE_LOGD("OnMtuInfoChanged In");
        if (impl_.serverEventHandler_) {
            impl_.serverEventHandler_->PostAsyncTask(
                    [serverId, connectId, info, errCode]() {
                        AdvancedSettingManager().GetInstance()->ASProcessSsapsMtuInfoChanged(serverId, connectId,
                            info, errCode);
                    }, 0);
        }
        impl_.callbacks_.ForEach([serverId, connectId, &info, errCode](sptr<ISleSsapServerCallback> callback) {
            callback->OnMtuInfoChanged(serverId, connectId, info.mtuSize, info.version, errCode);
        });
    }
private:
    SleSsapServerServer::SleSsapServerServerImpl &impl_;
};

SleSsapServerServer::SleSsapServerServerImpl::SleSsapServerServerImpl()
{
    SLE_LOGI("SleSsapServerServerImpl In");
    callbackImpl_ = std::make_unique<SleSsapServerCallbackImpl>(*this);
    SLE_ASSERT_AND_RETURN_LOG(callbackImpl_, "callbackImpl null error!");

    serverService_ = SleSsapServerService::GetInstance();
    SLE_ASSERT_AND_RETURN_LOG(serverService_, "ssap sever service instance null error!");

    SleErrorCode ret = serverService_->RegisterSsapServerCallback(*callbackImpl_.get());
    SLE_ASSERT_AND_RETURN_LOG(ret == SLE_NO_ERROR, "register ssaps callback failed!");

    adapterManager_ = SleAdapterManager::GetInstance();
    SLE_ASSERT_AND_RETURN_LOG(adapterManager_, "adapter manager instance null error!");

    serverEventRunner_ = AppExecFwk::EventRunner::Create(SLE_SERVER_RUNNER_WORK_THREAD);
    SLE_ASSERT_AND_RETURN_LOG(serverEventRunner_ != nullptr, "create serverEventRunner_ fail");
    serverEventHandler_ = std::make_shared<SleServerEventHandler>(serverEventRunner_);
    SLE_ASSERT_AND_RETURN_LOG(serverEventHandler_ != nullptr, "create serverEventHandler_ fail");
}

SleSsapServerServer::SleSsapServerServerImpl::~SleSsapServerServerImpl()
{
    SLE_LOGI("enter");
    SLE_ASSERT_AND_RETURN_LOG(callbackImpl_, "callbackImpl null error!");
    SLE_ASSERT_AND_RETURN_LOG(serverService_, "ssap server service instance null error!");
    SleErrorCode ret = serverService_->UnregisterSsapServerCallback(*callbackImpl_.get());
    SLE_ASSERT_AND_RETURN_LOG(ret == SLE_NO_ERROR, "unregister ssap server callback failed!");
}

SleErrorCode SleSsapServerServer::SleSsapServerServerImpl::CheckOperation()
{
    SLE_ASSERT_AND_RETURN_RET_LOG(serverService_, SLE_ERR_NOT_READY, "ssap server service instance null error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(adapterManager_, SLE_ERR_NOT_READY, "adapter manager instance null error!");
    int32_t state;
    SleErrorCode ret = adapterManager_->GetState(state);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "get sle state failed!");
    SLE_ASSERT_AND_RETURN_RET_LOG(state == SLE_HOST_STATE_ENABLED, SLE_ERR_STATUS_WRONG,
        "host state(%{public}s) error!", SleDeviceStateStr(state));
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapServerServer::SleSsapServerServerImpl::RegisterSsapServer(
    const Uuid &uuid, uint8_t &serverId, const sptr<ISleSsapServerCallback> &callback)
{
    auto func = std::bind(&SleSsapServerServer::SleSsapServerServerImpl::UnregisterSsapServerInner,
        this, std::placeholders::_1, std::placeholders::_2);
    SLE_ASSERT_AND_RETURN_RET_LOG(callbacks_.Register(callback, func, serverId), SLE_ERR_FAILED,
        "register ssap server callback failed!");
    SleErrorCode ret = serverService_->RegisterSsapServer(uuid, serverId);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "register ssap server failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapServerServer::SleSsapServerServerImpl::UnregisterSsapServerInner(
    const sptr<ISleSsapServerCallback> &callback, uint8_t serverId)
{
    return SleSsapServerServer::SleSsapServerServerImpl::UnregisterSsapServer(serverId, callback);
}

SleErrorCode SleSsapServerServer::SleSsapServerServerImpl::UnregisterSsapServer(
    uint8_t serverId, const sptr<ISleSsapServerCallback> &callback)
{
    SLE_ASSERT_AND_RETURN_RET_LOG(callbacks_.Unregister(callback), SLE_ERR_FAILED,
        "unregister ssap server callback failed!");
    SleErrorCode ret = serverService_->UnregisterSsapServer(serverId);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "unregister ssap server failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapServerServer::SleSsapServerServerImpl::AddService(
    uint8_t serverId, const Uuid &uuid, bool isPrimary, uint16_t &handle)
{
    SleErrorCode ret = serverService_->AddService(serverId, uuid, isPrimary, handle);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "add service failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapServerServer::SleSsapServerServerImpl::AddProperty(
    uint8_t serverId, uint16_t serviceHandle, const SsapServerPropertyParam &param, uint16_t &handle)
{
    SleErrorCode ret = serverService_->AddProperty(serverId, serviceHandle, param, handle);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "add property failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapServerServer::SleSsapServerServerImpl::AddDescriptor(
    uint8_t serverId, uint16_t serviceHandle, uint16_t propHandle, const SsapServerDescriptorParam &param)
{
    SleErrorCode ret = serverService_->AddDescriptor(serverId, serviceHandle, propHandle, param);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "add descriptor failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapServerServer::SleSsapServerServerImpl::RemoveAllServices(uint8_t serverId)
{
    SleErrorCode ret = serverService_->RemoveAllServices(serverId);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "remove all services failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapServerServer::SleSsapServerServerImpl::StartService(uint8_t serverId, uint16_t serviceHandle)
{
    SleErrorCode ret = serverService_->StartService(serverId, serviceHandle);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "start service failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapServerServer::SleSsapServerServerImpl::SendResponse(
    uint8_t serverId, uint16_t connectId, const SsapServerSendRspParam &param)
{
    SleErrorCode ret = serverService_->SendResponse(serverId, connectId, param);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "send response failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapServerServer::SleSsapServerServerImpl::NotifyIndicate(
    uint8_t serverId, uint16_t connectId, const SsapServerNotifyParam &param)
{
    SleErrorCode ret = serverService_->NotifyIndicate(serverId, connectId, param);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "notify indicate failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapServerServer::SleSsapServerServerImpl::NotifyIndicateByUuid(
    uint8_t serverId, uint16_t connectId, const SsapServerNotyfyByUuidParam &param)
{
    SleErrorCode ret = serverService_->NotifyIndicateByUuid(serverId, connectId, param);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "notify indicate by uuid failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapServerServer::SleSsapServerServerImpl::SetServerMtuInfo(
    uint8_t serverId, uint32_t mtu, uint16_t version)
{
    SleErrorCode ret = serverService_->SetServerMtuInfo(serverId, mtu, version);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "set server mtu info failed!");
    return SLE_NO_ERROR;
}

SleSsapServerServer::SleSsapServerServer()
{
    SLE_LOGI("enter");
    pimpl_ = std::make_unique<SleSsapServerServerImpl>();
    SLE_ASSERT_AND_RETURN_LOG(pimpl_, "pimpl null error!");
}

SleSsapServerServer::~SleSsapServerServer(){}

SleErrorCode SleSsapServerServer::RegisterSsapServer(
    const Uuid &uuid, uint8_t &serverId, const sptr<ISleSsapServerCallback> &callback)
{
    SLE_LOGD("RegisterSsapServer In");
    SLE_ASSERT_AND_RETURN_RET_LOG(callback, SLE_ERR_INVALID_PARAM, "callback null error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(pimpl_, SLE_ERR_NOT_READY, "pimpl null error!");
    SleErrorCode ret = pimpl_->RegisterSsapServer(uuid, serverId, callback);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "register server failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapServerServer::UnregisterSsapServer(uint8_t serverId, const sptr<ISleSsapServerCallback> &callback)
{
    SLE_LOGD("UnregisterSsapServer In");
    SLE_ASSERT_AND_RETURN_RET_LOG(callback, SLE_ERR_INVALID_PARAM, "callback null error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(pimpl_, SLE_ERR_NOT_READY, "pimpl null error!");
    SleErrorCode ret = pimpl_->UnregisterSsapServer(serverId, callback);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "unregister ssap server failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapServerServer::AddService(uint8_t serverId, const Uuid &uuid, bool isPrimary, uint16_t &handle)
{
    SLE_LOGD("AddService In");
    SLE_ASSERT_AND_RETURN_RET_LOG(pimpl_, SLE_ERR_NOT_READY, "pimpl null error!");
    SleErrorCode ret = pimpl_->CheckOperation();
    ret = pimpl_->AddService(serverId, uuid, isPrimary, handle);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "add service failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapServerServer::AddProperty(
    uint8_t serverId, uint16_t serviceHandle, const SsapServerPropertyParam &param, uint16_t &handle)
{
    SLE_LOGD("AddProperty In");
    SLE_ASSERT_AND_RETURN_RET_LOG(pimpl_, SLE_ERR_NOT_READY, "pimpl null error!");
    SleErrorCode ret = pimpl_->CheckOperation();
    ret = pimpl_->AddProperty(serverId, serviceHandle, param, handle);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "add property failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapServerServer::AddDescriptor(
    uint8_t serverId, uint16_t serviceHandle, uint16_t propHandle, const SsapServerDescriptorParam &param)
{
    SLE_LOGD("AddDescriptor In");
    SLE_ASSERT_AND_RETURN_RET_LOG(pimpl_, SLE_ERR_NOT_READY, "pimpl null error!");
    SleErrorCode ret = pimpl_->CheckOperation();
    ret = pimpl_->AddDescriptor(serverId, serviceHandle, propHandle, param);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "add descriptor failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapServerServer::RemoveAllServices(uint8_t serverId)
{
    SLE_LOGD("RemoveAllServices In");
    SLE_ASSERT_AND_RETURN_RET_LOG(pimpl_, SLE_ERR_NOT_READY, "pimpl null error!");
    SleErrorCode ret = pimpl_->CheckOperation();
    ret = pimpl_->RemoveAllServices(serverId);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "remove all services failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapServerServer::StartService(uint8_t serverId, uint16_t serviceHandle)
{
    SLE_LOGD("StartService In");
    SLE_ASSERT_AND_RETURN_RET_LOG(pimpl_, SLE_ERR_NOT_READY, "pimpl null error!");
    SleErrorCode ret = pimpl_->CheckOperation();
    ret = pimpl_->StartService(serverId, serviceHandle);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "start service failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapServerServer::SendResponse(
    uint8_t serverId, uint16_t connectId, const SsapServerSendRspParam &param)
{
    SLE_LOGD("SendResponse In");
    SLE_ASSERT_AND_RETURN_RET_LOG(pimpl_, SLE_ERR_NOT_READY, "pimpl null error!");
    SleErrorCode ret = pimpl_->CheckOperation();
    ret = pimpl_->SendResponse(serverId, connectId, param);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "send response failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapServerServer::NotifyIndicate(
    uint8_t serverId, uint16_t connectId, const SsapServerNotifyParam &param)
{
#if 0
    SLE_LOGD("NotifyIndicate In");
#endif
    SLE_ASSERT_AND_RETURN_RET_LOG(pimpl_, SLE_ERR_NOT_READY, "pimpl null error!");
    SleErrorCode ret = pimpl_->CheckOperation();
    ret = pimpl_->NotifyIndicate(serverId, connectId, param);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "notify indicate failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapServerServer::NotifyIndicateByUuid(
    uint8_t serverId, uint16_t connectId, const SsapServerNotyfyByUuidParam &param)
{
    SLE_LOGD("NotifyIndicateByUuid In");
    SLE_ASSERT_AND_RETURN_RET_LOG(pimpl_, SLE_ERR_NOT_READY, "pimpl null error!");
    SleErrorCode ret = pimpl_->CheckOperation();
    ret = pimpl_->NotifyIndicateByUuid(serverId, connectId, param);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "notify indicate by uuid failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapServerServer::SetServerMtuInfo(uint8_t serverId, uint32_t mtu, uint16_t version)
{
    SLE_LOGD("SetServerMtuInfo In");
    SLE_ASSERT_AND_RETURN_RET_LOG(pimpl_, SLE_ERR_NOT_READY, "pimpl null error!");
    SleErrorCode ret = pimpl_->CheckOperation();
    ret = pimpl_->SetServerMtuInfo(serverId, mtu, version);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "set server mtu info failed!");
    return SLE_NO_ERROR;
}
} // SleStandard
} // NearLink
} // OHOS